package com.calvin.springcloud.controller;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import com.calvin.springcloud.base.ResponseResult;
import com.calvin.springcloud.feign.user.UserFei;
import com.calvin.springcloud.feign.user.fallback.UserFeignFallBack;
import com.calvin.springcloud.model.user.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import com.netflix.hystrix.exception.HystrixTimeoutException;

import lombok.extern.slf4j.Slf4j;

@RestController
@Slf4j
public class ConsumerUserController {

	/**
	 * 理解：消费者，不应该有service层~ 提供多种便捷访问远程http服务的方法，简单的Restful服务模板~
	 */
	@Autowired
	private RestTemplate restTemplate;
	@Autowired
	private UserFei userFeiFallback;
	
	private static final String eureka_server_url = "http://PROVIDER-USER";

	
	@RequestMapping("/consumerUser/getUserList")
	public ResponseResult<Object> getUserList() {
		ResponseResult<Object> resp = restTemplate.getForObject(eureka_server_url + "/user/getUserList", ResponseResult.class);
		return resp;
	}
		
	@GetMapping("/consumerUser/findUser/{userId}/{userName}")
	public ResponseResult<User> findUser(@PathVariable Long userId, @PathVariable String userName) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("userId", userId);
		paramMap.put("userName", userName);
		ResponseResult<User> user = restTemplate.getForObject(
				eureka_server_url + "/user/findUser/{userId}/{userName}", ResponseResult.class,
				paramMap);
		return user;
	}

//////////////////////////////////////////////////////青铜 整合Hystrix/////////////////////////////////////////////////////////////////////
	//缺点：
		//1.每个需要降级服务的方法都需要添加fallback方法，代码耦合度高，可读性差，后期难以维护
	@HystrixCommand(fallbackMethod="findUserFallback",ignoreExceptions= {IllegalStateException.class})
	@GetMapping("/consumerUser/findUserHystrix/{userId}/{userName}")
	public ResponseResult<User> findUserHystrix(@PathVariable Long userId, @PathVariable String userName) {
		Map<String, Object> paramMap = new HashMap<String, Object>();
		paramMap.put("userId", userId);
		paramMap.put("userName", userName);
		
		ResponseResult<User> user = restTemplate.getForObject(
				eureka_server_url + "/user/findUser/{userId}/{userName}", ResponseResult.class,
				paramMap);
		return user;
	}
	
	public ResponseResult<User> findUserFallback(Long userId,String userName,Throwable throwable) {
		log.error("[ConsumerUserController][findUserFallback] error," +throwable);
		return new ResponseResult<User>().fail("调用异常，服务降级处理");
	}
//////////////////////////////////////////////////////青铜 整合Hystrix/////////////////////////////////////////////////////////////////////
	
	

//////////////////////////////////////////////////////黄金 整合Hystrix/////////////////////////////////////////////////////////////////////
	
	//开启服务熔断，满足条件则调用回退方法
	@HystrixCommand(commandProperties = {
	        @HystrixProperty(name = "circuitBreaker.enabled",value = "true"),//开启熔断
	        //时间窗口期(时间范围)，例如5秒，结合下面两个注解使用，5秒内10次请求50%的失败率则打开断路器
	        @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "5000"),
	        @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "10"), 
	        //失败率阈值，例如在请求数量（circuitBreaker.requestVolumeThreshold）中，如果请求数失败的百分比超过50，则断路器启用
	        @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
	
	})
	@GetMapping("/consumerUser/findUserFeign/{userId}/{userName}")
	public ResponseResult<User> findUserFeign(@PathVariable Long userId, @PathVariable String userName) {
		return userFeiFallback.findUser(userId, userName);
	}
	
//////////////////////////////////////////////////////黄金 整合Hystrix/////////////////////////////////////////////////////////////////////
}
